<?php
/***********************************************************************
 * @package    	IvanEngine
 * @subpackage 	Core
 * @author     	Ivan <ivanzx@msn.com>
 * @created    	2010-05-13
 ***********************************************************************/
if(defined("IVANENGINE_CORE_EXCEPTION_VALIDATOR"))
	die("Redefinition macro in :".__FILE__."(".__LINE__.")");
define("IVANENGINE_CORE_EXCEPTION_VALIDATOR", true);

require_once (dirname(__FILE__).'/ExceptionValidator.php');

class CExceptionValidatorMap extends CException
{
	protected
	    $m_errors       = array(),
	    $m_globalErrors = array(),
	    $m_namedErrors  = array(),
	    $m_count        = 0;
	    
	public function __construct(CValidatorBase $validator, $errors = array())
  	{
	    $this->validator = $validator;
	    $this->arguments = array();
	
	    $this->AddErrors($errors);
	    
	    parent::__construct($this->m_message);
  	}
  	
	public function AddError(CExceptionValidator $error, $name = null)
  	{
	    if (is_null($name) || is_integer($name))
	    {
	      	if ($error instanceof CExceptionValidatorMap)
	      	{
	        	$this->AddErrors($error);
	      	}
	      	else
	      	{
	        	$this->m_globalErrors[] = $error;
	        	$this->m_errors[] = $error;
	      	}
	    }
	    else
	    {
	      	if (!isset($this->m_namedErrors[$name]) && !$error instanceof CExceptionValidatorMap)
	      	{
	        	$this->m_namedErrors[$name] = $error;
	        	$this->m_errors[$name] = $error;
	      	}
	      	else
	      	{
		        if (!isset($this->m_namedErrors[$name]))
		        {
		          	$this->m_namedErrors[$name] = new CExceptionValidatorMap($error->GetValidator());
		          	$this->m_errors[$name] = new CExceptionValidatorMap($error->GetValidator());
		        }
		        else if (!$this->m_namedErrors[$name] instanceof CExceptionValidatorMap)
		        {
		          	$current = $this->m_namedErrors[$name];
		          	$this->m_namedErrors[$name] = new CExceptionValidatorMap($current->GetValidator());
		          	$this->m_errors[$name] = new CExceptionValidatorMap($current->GetValidator());
		
		          	$method = $current instanceof CExceptionValidatorMap ? 'AddErrors' : 'AddError';
		          	$this->m_namedErrors[$name]->$method($current);
		          	$this->m_errors[$name]->$method($current);
		        }
		
		        $method = $error instanceof CExceptionValidatorMap ? 'AddErrors' : 'AddError';
		        $this->m_namedErrors[$name]->$method($error);
		        $this->m_errors[$name]->$method($error);
	      	}
	    }
	
	    $this->UpdateCode();
	    $this->UpdateMessage();
  	}
  	
	public function AddErrors($errors)
  	{
	    if ($errors instanceof CExceptionValidatorMap)
	    {
	      	foreach ($errors->GetGlobalErrors() as $error)
	      	{
	        	$this->AddError($error);
	      	}
	
	      	foreach ($errors->GetNamedErrors() as $name => $error)
	      	{
	        	$this->AddError($error, (string) $name);
	      	}
	    }
	    else
	    {
	      	foreach ($errors as $name => $error)
	      	{
	        	$this->AddError($error, $name);
	      	}
	    }
  	}
  	
	public function GetErrors()
  	{
    	return $this->m_errors;
  	}

  	/**
   	* Gets an array of all named errors
   	*
   	* @return array An array of sfValidatorError instances
   	*/
  	public function GetNamedErrors()
  	{
    	return $this->m_namedErrors;
  	}

  	/**
   	* Gets an array of all global errors
   	*
   	* @return array An array of sfValidatorError instances
   	*/
  	public function GetGlobalErrors()
  	{
    	return $this->m_globalErrors;
  	}

  	/**
   	* Updates the exception error code according to the current errors.
   	*/
  	protected function UpdateCode()
  	{
    	$this->code = implode(' ', array_merge(
      		array_map(create_function('$e', 'return $e->getCode();'), $this->m_globalErrors),
      		array_map(create_function('$n,$e', 'return $n.\' [\'.$e->getCode().\']\';'), array_keys($this->m_namedErrors), array_values($this->m_namedErrors))
    	));
  	}

  	/**
   	* Updates the exception error message according to the current errors.
   	*/
  	protected function UpdateMessage()
  	{
    	$this->m_message = implode(' ', array_merge(
      		array_map(create_function('$e', 'return $e->getMessage();'), $this->m_globalErrors),
      		array_map(create_function('$n,$e', 'return $n.\' [\'.$e->getMessage().\']\';'), array_keys($this->m_namedErrors), array_values($this->m_namedErrors))
    	));
  	}
}

?>